﻿using System;
using System.Collections.Generic;

namespace HEFramework
{
    #region 场景

    /// <summary>
    ///
    /// 场景枚举
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-11-30 11:05:59
    /// ----------------------------------------
    /// </summary>
    [Flags]
    public enum eSceneType : long
    {
        None = 0,

        //初始化从这里开始
        Main = 1,
        Game = 1 << 30,
        Test = 1 << 31,
        
        //Current = 1L << 31,
        All = long.MaxValue,
    }

    /// <summary>
    ///
    /// 场景帮助器
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-11-30 11:06:06
    /// ----------------------------------------
    /// </summary>
    public static class SceneTypeHelper
    {
        public static bool HasSameFlag(this eSceneType _a, eSceneType _b)
        {
            if (((ulong)_a & (ulong)_b) == 0)
            {
                return false;
            }

            return true;
        }
    }

    /// <summary>
    ///
    /// 场景接口
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-11-30 11:03:39
    /// ----------------------------------------
    /// </summary>
    public interface IScene
    {
        eSceneType SceneType { get; set; }
    }

    #endregion

    #region 事件

    /// <summary>
    ///
    /// 事件接口
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-11-30 11:03:47
    /// ----------------------------------------
    /// </summary>
    public interface IEvent
    {
        Type Type { get; }
    }


    /// <summary>
    ///
    /// 事件抽象类
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-11-30 11:05:54
    /// ----------------------------------------
    /// </summary>
    public abstract class AEvent<S, A> : IEvent where S : class, IScene where A : struct
    {
        public Type Type
        {
            get { return typeof(A); }
        }

        protected abstract HETask Run(S _scene, A _a);

        public async HETask Handle(S _scene, A _a)
        {
            try
            {
                await Run(_scene, _a);
            }
            catch (Exception e)
            {
                Log.Error(e);
            }
        }
    }

    #endregion

    #region 方法

    /// <summary>
    ///
    /// 方法接口
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-11-30 11:13:38
    /// ----------------------------------------
    /// </summary>
    public interface IInvoke
    {
        Type Type { get; }
    }

    /// <summary>
    ///
    /// 方法抽象类
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-11-30 11:13:49
    /// ----------------------------------------
    /// </summary>
    public abstract class AInvokeHandler<A> : IInvoke where A : struct
    {
        public Type Type
        {
            get { return typeof(A); }
        }

        public abstract void Handle(A _args);
    }

    /// <summary>
    ///
    /// 方法抽象类（返回结果）
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-11-30 11:16:01
    /// ----------------------------------------
    /// </summary>
    public abstract class AInvokeHandler<A, T> : IInvoke where A : struct
    {
        public Type Type
        {
            get { return typeof(A); }
        }

        public abstract T Handle(A _args);
    }

    #endregion


    /// <summary>
    ///
    /// 事件监听者
    /// 
    /// ----------------------------------------
    /// 作者 hep
    /// 创建时间：2023-11-30 11:07:10
    /// ----------------------------------------
    /// </summary>
    [Code]
    public class EventListener : Singleton<EventListener>, ISingletonAwake
    {
        /// <summary>
        ///
        /// 事件消息 【事件->单对多】【方法-单对单】
        /// 
        /// ----------------------------------------
        /// 作者 hep
        /// 创建时间：2023-11-30 11:07:37
        /// ----------------------------------------
        /// </summary>
        private class EventInfo
        {
            public IEvent IEvent { get; }

            public eSceneType SceneType { get; }

            public EventInfo(IEvent _event, eSceneType _sceneType)
            {
                this.IEvent = _event;
                this.SceneType = _sceneType;
            }
        }

        private readonly Dictionary<Type, List<EventInfo>> allEvents = new();

        private Dictionary<Type, Dictionary<long, object>> allInvokes = new();

        public void Awake()
        {
            CodeOwner codeOwner = CodeOwner.Instance;
            //绑定所有场景事件信息
            //获取所有打上事件标签的类
            foreach (Type type in codeOwner.GetTypes(typeof(EventAttribute)))
            {
                //创建实体
                IEvent obj = Activator.CreateInstance(type) as IEvent;
                if (obj == null)
                {
                    throw new Exception($"Type not is AEvent: {type.Name}");
                }

                //拿到对应类的事件标签属性信息
                object[] attrs = type.GetCustomAttributes(typeof(EventAttribute), false);
                foreach (object attr in attrs)
                {
                    EventAttribute eventAttribute = attr as EventAttribute;
                    Type eventType = obj.Type;
                    EventInfo eventInfo = new(obj, eventAttribute.ESceneType);
                    if (!this.allEvents.ContainsKey(eventType))
                    {
                        this.allEvents.Add(eventType, new List<EventInfo>());
                    }

                    //【事件类型-事件信息】字典
                    this.allEvents[eventType].Add(eventInfo);
                }
            }


            //绑定所有方法信息
            //获取所有打上方法标签的类
            foreach (Type type in codeOwner.GetTypes(typeof(InvokeAttribute)))
            {
                object obj = Activator.CreateInstance(type);
                IInvoke iInvoke = obj as IInvoke;
                if (iInvoke == null)
                {
                    throw new Exception($"Type not is callback: {type.Name}");
                }

                object[] attrs = type.GetCustomAttributes(typeof(InvokeAttribute), false);
                foreach (object attr in attrs)
                {
                    //iInvoke.Type = 事件 = 参数
                    if (!this.allInvokes.TryGetValue(iInvoke.Type, out var dict))
                    {
                        dict = new Dictionary<long, object>();
                        this.allInvokes.Add(iInvoke.Type, dict);
                    }

                    InvokeAttribute invokeAttribute = attr as InvokeAttribute;

                    try
                    {
                        // invokeAttribute.Type = 场景
                        dict.Add(invokeAttribute.Type, obj);
                    }
                    catch (Exception e)
                    {
                        throw new Exception($"Action type duplicate: {iInvoke.Type.Name} {invokeAttribute.Type}", e);
                    }
                }
            }
        }

        public async HETask PublishAsync<S, T>(S _scene, T _a) where S : class, IScene where T : struct
        {
            List<EventInfo> events;
            if (!this.allEvents.TryGetValue(typeof(T), out events))
            {
                return;
            }

            using ListObject<HETask> list = ListObject<HETask>.Create();

            foreach (EventInfo eventInfo in events)
            {
                //场景不对，跳过
                if (!_scene.SceneType.HasSameFlag(eventInfo.SceneType))
                {
                    continue;
                }

                if (!(eventInfo.IEvent is AEvent<S, T> aEvent))
                {
                    Log.Error($"Event error: {eventInfo.IEvent.GetType().FullName}");
                    continue;
                }

                list.Add(aEvent.Handle(_scene, _a));
            }

            try
            {
                await HETaskHelper.WaitAll(list);
            }
            catch (Exception e)
            {
                Log.Error(e);
            }
        }

        public void Publish<S, T>(S _scene, T _a) where S : class, IScene where T : struct
        {
            List<EventInfo> events;
            if (!this.allEvents.TryGetValue(typeof(T), out events))
            {
                return;
            }

            eSceneType eSceneType = _scene.SceneType;
            foreach (EventInfo eventInfo in events)
            {
                if (!eSceneType.HasSameFlag(eventInfo.SceneType))
                {
                    continue;
                }


                if (!(eventInfo.IEvent is AEvent<S, T> aEvent))
                {
                    Log.Error($"Event error: {eventInfo.IEvent.GetType().FullName}");
                    continue;
                }

                aEvent.Handle(_scene, _a).Coroutine();
            }
        }

        // Invoke跟Publish的区别(特别注意)
        // Invoke类似函数，必须有被调用方，否则异常，调用者跟被调用者属于同一模块
        // 既然Invoke跟函数一样，那么为什么不使用函数呢? 因为有时候不方便直接调用，比如Config加载，在客户端跟服务端加载方式不一样。
        // 注意，不要把Invoke当函数使用，这样会造成代码可读性降低，能用函数不要用Invoke
        // publish是事件，抛出去可以没人订阅，调用者跟被调用者属于两个模块，比如任务系统需要知道道具使用的信息，则订阅道具使用事件
        public void Invoke<A>(long _type, A _args) where A : struct
        {
            if (!this.allInvokes.TryGetValue(typeof(A), out var invokeHandlers))
            {
                throw new Exception($"Invoke error1: {_type} {typeof(A).FullName}");
            }

            if (!invokeHandlers.TryGetValue(_type, out var invokeHandler))
            {
                throw new Exception($"Invoke error2: {_type} {typeof(A).FullName}");
            }

            var aInvokeHandler = invokeHandler as AInvokeHandler<A>;
            if (aInvokeHandler == null)
            {
                throw new Exception($"Invoke error3, not AInvokeHandler: {_type} {typeof(A).FullName}");
            }

            aInvokeHandler.Handle(_args);
        }

        public T Invoke<A, T>(long _type, A _args) where A : struct
        {
            if (!this.allInvokes.TryGetValue(typeof(A), out var invokeHandlers))
            {
                throw new Exception($"Invoke error4: {_type} {typeof(A).FullName}");
            }

            if (!invokeHandlers.TryGetValue(_type, out var invokeHandler))
            {
                throw new Exception($"Invoke error5: {_type} {typeof(A).FullName}");
            }

            var aInvokeHandler = invokeHandler as AInvokeHandler<A, T>;
            if (aInvokeHandler == null)
            {
                throw new Exception($"Invoke error6, not AInvokeHandler: {_type} {typeof(A).FullName} {typeof(T).FullName} ");
            }

            return aInvokeHandler.Handle(_args);
        }

        public void Invoke<A>(A _args) where A : struct
        {
            Invoke(0, _args);
        }

        public T Invoke<A, T>(A _args) where A : struct
        {
            return Invoke<A, T>(0, _args);
        }
    }
}